home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 19 / CD_ASCQ_19_010295.iso / dos / prg / pas / swag / oop.swg / 0037_Recursive Expression Pars.pas < prev    next >
Pascal/Delphi Source File  |  1994-02-15  |  16KB  |  763 lines

  1. UNIT PARSER;
  2.  
  3. {  recursive descent expression Parser.
  4.  
  5.    Based on the parser by Herbert Shildt as shown in
  6.    Advanced C
  7.    Osborn McGraw-Hill
  8.  
  9.    Ported to Pascal by
  10.  
  11.    (C) M.Fiel 1993 Vienna - Austria
  12.    CompuServe ID : 100041,2007
  13.  
  14.    for further infos refer to this book.
  15.  
  16.    Use freely if you find it useful.
  17.  
  18. }
  19. {$R+}
  20.  
  21. INTERFACE
  22.  
  23.   USES
  24.     Objects,ParTools;
  25.  
  26.   CONST
  27.     MaxParserVars = 100; { Max Count of Variables fo PVarParser }
  28.  
  29.   TYPE
  30.  
  31. { PMathParser evaluates expressions like (-(10*5)/27) * 128  no variables }
  32.  
  33.     PMathParser = ^TMathParser;
  34.     TMathParser = object(TObject)
  35.  
  36.       ToParse   : PString;    { the string to parse }
  37.       ExprPos   : Integer;    { aktuall position in the string }
  38.       TokenType : Integer;    { Variable delimiter...}
  39.       Token     : String;     { the aktuell token }
  40.  
  41.       Result    : Real;       { the result of the expression }
  42.  
  43.       constructor Init;
  44.       destructor  Done; virtual;
  45.  
  46.       function    Evaluate(Expression:String) : Real;
  47.       { expression is the string which is to be evaluated
  48.       calls function Parse}
  49.  
  50.       function    GetNextToken : Boolean; virtual;
  51.       function    GetPart : String; virtual;
  52.       function    isDelimiter : Boolean; virtual;
  53.  
  54.       function    AddSub : Boolean; virtual;
  55.       { checks for Addition or Substr and calls MulDiv }
  56.       function    MulDiv : Boolean; virtual;
  57.       { checks for Multiplikation or Div. and calls Unary }
  58.       function    Unary  : Boolean; virtual;
  59.       { checks for Unary (+/-) and calls Parant }
  60.       function    Parant : Boolean; virtual;
  61.       { checks for paratheses and if necessary calls Parse --> go recursive }
  62.  
  63.       function    Primitive : Boolean; virtual;
  64.       { evaluates constatn value }
  65.  
  66.       function    Parse : Boolean; virtual;
  67.       { parse not necessary in this version (call addsub instead) but is
  68.         needed in descents }
  69.  
  70.     end;
  71.  
  72. { VarParser can Handle Variables and epressions like
  73.   A=10.78
  74.   B=20.45
  75.   A*(B-10)+5
  76.   .
  77.   .
  78.   .
  79. }
  80.     PVarParser = ^TVarParser;
  81.     TVarParser = object(TMathParser)
  82.  
  83.       Vars : PParserVarColl;{Container of Variables defined in Unit ParTools}
  84.  
  85.       constructor Init;
  86.       destructor  Done; virtual;
  87.  
  88.       function    Primitive : Boolean; virtual;
  89.       function    Parse : Boolean; virtual;
  90.       { Calls Checckassign }
  91.  
  92.       function    CheckAssign : Boolean; virtual;
  93.       { checks assignments : ex. A=12 }
  94.       procedure   ClearVars; virtual;
  95.       { clears all variables }
  96.  
  97.     end;
  98.  
  99. IMPLEMENTATION
  100.  
  101.   CONST                { defines wich type a token is }
  102.     tError     = 0;
  103.     tVariable  = 1;
  104.     tDelimiter = 2;
  105.     tNumber    = 3;
  106.     tConstValue = 4;
  107.  
  108.   constructor TMathParser.Init;
  109.     begin
  110.       if not inherited Init then FAIL;
  111.       ExprPos:=0;
  112.       Token:='';
  113.     end;
  114.  
  115.   destructor TMathParser.Done;
  116.     begin
  117.       if (ToParse<>NIL) then DisposeStr(ToParse);
  118.       inherited Done;
  119.     end;
  120.  
  121.   function TMathParser.Evaluate(Expression:String) : Real;
  122.  
  123.     begin
  124.  
  125.       if (ToParse<>NIL) then DisposeStr(ToParse);
  126.       ToParse:=NewStr(Expression);
  127.  
  128.       result:=0.00;
  129.       ExprPos:=1;
  130.  
  131.       if GetNextToken then Parse;
  132.  
  133.       Evaluate:=result;
  134.  
  135.     end;
  136.  
  137.   function TMathParser.Parse : Boolean;
  138.     begin
  139.       Parse:=AddSub;
  140.     end;
  141.  
  142.   function TMathParser.GetNextToken : Boolean;
  143.     begin
  144.  
  145.       GetNextToken:=True;
  146.  
  147.       while ToParse^[ExprPos] = ' ' do inc(ExprPos);
  148.  
  149.       if (isDelimiter) then begin
  150.  
  151.         TokenType := tDelimiter;
  152.         Token:=ToParse^[ExprPos];
  153.         inc(ExprPos);
  154.  
  155.       end else begin
  156.  
  157.         case ToParse^[ExprPos] of
  158.  
  159.           '0'..'9':begin
  160.             TokenType := tNumber;
  161.             Token :=GetPart;
  162.           end;
  163.  
  164.           'A'..'Z','a'..'z' : begin
  165.             TokenType := tVariable;
  166.             Token:=GetPart;
  167.           end;
  168.  
  169.           else begin
  170.             TokenType := tError;
  171.             GetNextToken:=False;
  172.           end;
  173.  
  174.         end;
  175.  
  176.       end;
  177.  
  178.     end;
  179.  
  180.   function TMathParser.GetPart : String;
  181.     var
  182.       RetVal : String;
  183.     begin
  184.  
  185.       RetVal:='';
  186.  
  187.       while not(isDelimiter) do begin
  188.  
  189.         RetVal:=RetVal+ToParse^[ExprPos];
  190.  
  191.         if ExprPos<length(ToParse^) then
  192.           inc(ExprPos)
  193.         else begin
  194.           RetVal:=Trim(RetVal);
  195.           GetPart:=RetVal;
  196.           Exit;
  197.         end;
  198.  
  199.       end;
  200.  
  201.       RetVal:=Trim(RetVal);
  202.  
  203.       GetPart:=RetVal;
  204.  
  205.     end;
  206.  
  207.   function TMathParser.isDelimiter : Boolean;
  208.     begin
  209.       isDelimiter:=(Pos(ToParse^[ExprPos],'+-*/()=%')<>0);
  210.     end;
  211.  
  212.   function TMathParser.AddSub : Boolean;
  213.     var
  214.       Hold : Real;
  215.       OldToken : String;
  216.     begin
  217.  
  218.       AddSub:=True;
  219.  
  220.       if (MulDiv) then begin
  221.  
  222.         while (Pos(Token,'+-') > 0) do begin
  223.  
  224.           OldToken:=Token;
  225.           GetNextToken;
  226.  
  227.           Hold:=Result;
  228.  
  229.           if (MulDiv) then begin
  230.             if OldToken='+' then Result:=(Hold+Result) else Result:=(Hold-Result);
  231.           end else
  232.             AddSub:=False;
  233.  
  234.         end;
  235.  
  236.       end else
  237.         AddSub:=False;
  238.  
  239.     end;
  240.  
  241.   function TMathParser.MulDiv : Boolean;
  242.     var
  243.       Hold : Real;
  244.       PerHelp : Real;
  245.       OldToken : String;
  246.     begin
  247.  
  248.       MulDiv:=True;
  249.  
  250.       if (Unary) then begin
  251.  
  252.         while (Pos(Token,'*/%') > 0) do begin
  253.  
  254.           OldToken:=Token;
  255.           GetNextToken;
  256.           Hold:=Result;
  257.  
  258.           if (Unary) then begin
  259.  
  260.             case OldToken[1] of
  261.               '*':Result:=Hold*Result;
  262.  
  263.               '/':begin
  264.                 if (Result<> 0) then
  265.                   Result:=Hold/Result
  266.                 else begin
  267.                   OwnError('Division by zero');
  268.                   MulDiv:=False;
  269.                 end;
  270.               end;
  271.  
  272.               '%':begin
  273.                 PerHelp:=Hold/Result;
  274.                 Result:=Hold-(PerHelp*Result);
  275.               end;
  276.  
  277.             end;
  278.  
  279.           end else
  280.             MulDiv:=False;
  281.  
  282.         end;
  283.  
  284.       end else
  285.         MulDiv:=False;
  286.  
  287.     end;
  288.  
  289.   function TMathParser.Unary : Boolean;
  290.     var
  291.       UnaryHelp:Boolean;
  292.       OldToken : String;
  293.     begin
  294.  
  295.       Unary:=True;
  296.  
  297.       UnaryHelp:=False;
  298.  
  299.       if (Pos(Token,'-+') >0) then begin
  300.         OldToken:=Token;
  301.         UnaryHelp:=True;
  302.         GetNextToken;
  303.       end;
  304.  
  305.       if (Parant) then begin
  306.         if (UnaryHelp and (OldToken = '-')) then Result:=-(Result);
  307.       end else
  308.         Unary:=False;
  309.  
  310.     end;
  311.  
  312.   function TMathParser.Parant : Boolean;
  313.     begin
  314.  
  315.       Parant:=True;
  316.  
  317.       if ((TokenType = tDelimiter) and (Token = '(')) then begin
  318.  
  319.         GetNextToken;
  320.  
  321.         if (Parse) then begin
  322.  
  323.           if (Token <> ')') then begin
  324.             OwnError('unbalanced parantheses');
  325.             Parant:=False;
  326.           end;
  327.  
  328.         end else
  329.           Parant:=False;
  330.  
  331.         GetNextToken;
  332.  
  333.       end else
  334.  
  335.         Parant:=Primitive;
  336.  
  337.     end;
  338.  
  339.   function TMathParser.Primitive : Boolean;
  340.     var
  341.       e:Integer;
  342.     begin
  343.  
  344.       Primitive:=True;
  345.  
  346.       if (TokenType = tNumber) then begin
  347.  
  348.         val(Token,Result,e);
  349.  
  350.         if (e<>0) then begin
  351.           OwnError('syntax error');
  352.           Primitive:=False;
  353.         end;
  354.  
  355.         GetNextToken;
  356.  
  357.       end;
  358.  
  359.     end;
  360.  
  361.  
  362. {****************************************************************************}
  363. {                          TVARPARSER                                        }
  364. {****************************************************************************}
  365.  
  366.   constructor TVarParser.Init;
  367.     begin
  368.       if not inherited Init then FAIL;
  369.       Vars:=New(PParserVarColl,Init(MaxParserVars,0));
  370.     end;
  371.  
  372.   destructor TVarParser.Done;
  373.     begin
  374.       Dispose(Vars,Done);
  375.       inherited Done;
  376.     end;
  377.  
  378.   function TVarParser.Primitive : Boolean;
  379.     begin
  380.  
  381.       Primitive:=True;
  382.  
  383.       if (inherited Primitive) then begin
  384.  
  385.         if (TokenType = tVariable) then begin
  386.           result:=Vars^.GetVar(Token);
  387.           GetNextToken;
  388.         end;
  389.  
  390.       end else
  391.         Primitive:=False;
  392.  
  393.     end;
  394.  
  395.  function TVarParser.Parse : Boolean;
  396.    begin
  397.      Parse:=CheckAssign;
  398.    end;
  399.  
  400.  function TVarParser.CheckAssign : Boolean;
  401.    var
  402.      OldToken : String;
  403.      OldType  : Integer;
  404.    begin
  405.  
  406.      if (TokenType = tVariable) then begin
  407.  
  408.        OldToken :=Token;
  409.        OldType := TokenType;
  410.  
  411.        GetNextToken;
  412.  
  413.        if (Token = '=') then begin
  414.  
  415.          GetNextToken;
  416.  
  417.          CheckAssign:=AddSub;
  418.          Vars^.SetValue(OLdToken,result);
  419.  
  420.          Exit;
  421.  
  422.        end else begin
  423.  
  424.          dec(ExprPos,length(Token));
  425.          Token:=OldToken;
  426.          TokenType:=OldType;
  427.  
  428.        end;
  429.  
  430.      end;
  431.  
  432.      CheckAssign := AddSub;
  433.  
  434.    end;
  435.  
  436.  procedure TVarParser.ClearVars;
  437.    begin
  438.      Vars^.FreeAll;
  439.    end;
  440.  
  441. END.
  442.  
  443. { -------------------------------- CUT HERE -----------------------}
  444.  
  445. UNIT PARTOOLS;
  446.  
  447. {
  448.    (C) M.Fiel 1993 Vienna - Austria
  449.    CompuServe ID : 100041,2007
  450.  
  451.    Use freely if you find it useful.
  452. }
  453.  
  454. INTERFACE
  455.  
  456.   USES
  457.     Objects;
  458.  
  459.   TYPE
  460.  
  461.     {Object to hold variable data for the TVarParser defined in Unit Parser}
  462.  
  463.     PParserVar = ^TParserVar;
  464.     TParserVar = object(TObject)
  465.  
  466.       Name : PString;
  467.       Value : Real;
  468.  
  469.       constructor Init(aName:String;aValue:Real);
  470.       destructor  Done; virtual;
  471.  
  472.       function    GetName : String; virtual;
  473.       function    GetValue : Real; virtual;
  474.       procedure   SetValue(NewValue : Real); virtual;
  475.  
  476.     end;
  477.  
  478.     {Container to hold TParserVar objects }
  479.  
  480.     PParserVarColl = ^TParserVarColl;
  481.     TParserVarColl = object(TCollection)
  482.  
  483.       procedure FreeItem(Item:Pointer); virtual;
  484.       function  GetVarIndex(Name:String) : Integer; virtual;
  485.       function  GetVar(Name:String) : Real; virtual;
  486.       procedure SetValue(Name:String;NewValue:Real); virtual;
  487.  
  488.     end;
  489.  
  490.    PStrColl = ^TStrColl;  { Container for Strings }
  491.    TStrColl = object(TCollection)
  492.      procedure  FreeItem(Item: Pointer); virtual;
  493.    end;
  494.  
  495.   procedure OwnError(S:String); { Shows a MsgBox with S }
  496.   function Trim(Line:String) : String; { Pads a String from End }
  497.   function MkStr(Len,Val:Byte): String;
  498.   { makes a String of length len and fills it with val }
  499.  
  500. IMPLEMENTATION
  501.  
  502.   USES
  503.     MsgBox;
  504.  
  505.   constructor TParserVar.Init(aName:String;aValue:Real);
  506.     begin
  507.       inherited Init;
  508.       Name:=NewStr(aName);
  509.       Value:=aValue;
  510.     end;
  511.  
  512.   destructor TParserVar.Done;
  513.     begin
  514.       DisposeStr(Name);
  515.       inherited Done;
  516.     end;
  517.  
  518.   function TParserVar.GetName : String;
  519.     begin
  520.       if Name<>NIL then GetName:=Name^ else GetName:='';
  521.     end;
  522.  
  523.   function TParserVar.GetValue : Real;
  524.     begin
  525.       GetValue:=Value;
  526.     end;
  527.  
  528.   procedure TParserVar.SetValue(NewValue : Real);
  529.     begin
  530.       Value:=NewValue;
  531.     end;
  532.  
  533.   procedure TParserVarColl.FreeItem(Item:Pointer);
  534.     begin
  535.       if (Item <> NIL) then Dispose(PParserVar(Item),Done);
  536.     end;
  537.  
  538.  
  539.   function TParserVarColl.GetVar(Name:String) : Real;
  540.     var
  541.       Index:Integer;
  542.     begin
  543.       Index:=GetVarIndex(Name);
  544.  
  545.       if (Index<>-1) then
  546.         GetVar:=PParserVar(At(Index))^.GetValue
  547.       else begin
  548.         OwnError('invalid variable');
  549.         GetVar:=0;
  550.       end;
  551.  
  552.     end;
  553.  
  554.   function TParserVarColl.GetVarIndex(Name:String) : Integer;
  555.  
  556.     function isName(P:PParserVar):Boolean;
  557.       begin
  558.         isName:=(P^.GetName = Name);
  559.       end;
  560.  
  561.     begin
  562.       GetVarIndex:=IndexOf(FirstThat(@isName));
  563.     end;
  564.  
  565.   procedure TParserVarColl.SetValue(Name:String;NewValue:Real);
  566.     var
  567.       Index : Integer;
  568.  
  569.     begin
  570.  
  571.       Index:=GetVarIndex(Name);
  572.  
  573.       if (Index <> -1) then
  574.         PParserVar(At(Index))^.SetValue(NewValue)
  575.       else
  576.         Insert(New(PParserVar,Init(Name,NewValue)));
  577.  
  578.     end;
  579.  
  580.   procedure OwnError(S:String);
  581.     begin
  582.        MessageBox(S,nil,mfError + mfOkButton);
  583.     end;
  584.  
  585.   function Trim(Line:String) : String;
  586.     var
  587.       Len: BYTE ABSOLUTE Line;
  588.     begin
  589.       while (Len > 0) AND (Line[Len] = ' ') DO Dec(Len);
  590.       Trim := Line;
  591.     end ;
  592.  
  593.   function MkStr (Len,Val:Byte): String;
  594.     var
  595.       S:String;
  596.     begin
  597.        S[0]:=chr(Len);
  598.        fillchar (S[1],Len,Val);
  599.        MkStr:=s;
  600.     end;
  601.  
  602.  procedure TStrColl.FreeItem(Item: Pointer);
  603.    begin
  604.      if Item<>Nil then DisposeStr(Item);
  605.    end;
  606.  
  607. END.
  608.  
  609. { -------------------------------- DEMO PROGRAM -----------------------}
  610.  
  611. PROGRAM PARDEMO;
  612.  
  613. {
  614.    (C) M.Fiel 1993 Vienna - Austria
  615.    CompuServe ID : 100041,2007
  616.  
  617.    Use freely if you find it useful.
  618.  
  619.    Demonstration of a Recursive descent Parser and a new Screensaver
  620.    object.
  621.  
  622.    Infos watch the units and the parser.txt file
  623.  
  624.    if problems or comments leave me a message or mail me.
  625.  
  626. }
  627.  
  628.  
  629.  
  630. USES
  631.   Objects,Drivers,Menus,Views,App,Dialogs,ScrSaver,TVParser;
  632.  
  633.   { NOTE  -  SCRSAVER UNIT CAN BE FOUND IN SWAG DISTRIBUTION ALSO !!}
  634.   {          AND WILL BE NEED BY THIS MODULE                        }
  635.  
  636. CONST
  637.   cmParser = 1001;
  638.   cmScreenSave = 1002;
  639.  
  640. TYPE
  641.  
  642.    PApp = ^Tapp;
  643.    TApp = object(TApplication)
  644.  
  645.       ScreenSaver : PScreenSaver; { defined in unit ScrSav }
  646.       {add the screensaver object to the application}
  647.  
  648.       constructor Init;
  649.  
  650.       procedure   HandleEvent (var event:Tevent); virtual;
  651.       procedure   InitMenuBar; virtual;
  652.       procedure   InitStatusLine; virtual;
  653.       procedure   ShowParser;
  654.       procedure   GetEvent(var Event: TEvent); virtual;
  655.  
  656.    end;
  657.  
  658.   VAR
  659.     XApplic: TApp;
  660.  
  661.    constructor TApp.Init;
  662.      begin
  663.        if not inherited Init then FAIL;
  664.  
  665.        ScreenSaver:=New(PScreenSaver,Init('I''m the Screensaver',180));
  666.        Insert(ScreenSaver);
  667.  
  668.      end;
  669.  
  670.   procedure TApp.GetEvent(var Event: TEvent);
  671.     begin
  672.       inherited GetEvent(Event);
  673.       ScreenSaver^.GetEvent(Event);  { don't forget this line }
  674.     end;
  675.  
  676.    procedure Tapp.InitStatusLine;
  677.  
  678.      var
  679.        R: TRect;
  680.      begin
  681.  
  682.        GetExtent(r);
  683.        R.A.Y := R.B.Y - 1;
  684.  
  685.        StatusLine:=New(PStatusLine, Init(R,
  686.  
  687.           NewStatusDef (0, 1000,
  688.              newstatuskey ('~F10~-Menu',kbF10,cmmenu,
  689.              newstatuskey ('~Alt-X~ Exit', kbaltx, cmQuit,
  690.           NIL)),
  691.  
  692.        NIL)));
  693.  
  694.      end;
  695.  
  696.    procedure Tapp.InitMenuBar;
  697.  
  698.      var
  699.        R : TRect;
  700.      begin
  701.  
  702.         GetExtent(R);
  703.         R.B.Y := R.A.Y + 1;
  704.  
  705.         MenuBar:=New(PMenuBar,Init(R,NewMenu(
  706.  
  707.            NewSubMenu('~≡~ ',hcNoContext,NewMenu(
  708.              NewItem('~Alt-X~ Exit','',kbAltX,cmQuit,hcNoContext,
  709.            NIL)),
  710.  
  711.            NewItem('~P~arser','',0,cmParser,hcNoContext,
  712.            NewItem('~S~creensave','',0,cmScreenSave,hcNoContext,
  713.  
  714.         Nil))))));
  715.     end;
  716.  
  717.   procedure TApp.ShowParser;
  718.     var
  719.       Parser:PVisionParser;
  720.     begin
  721.       Parser:=New(PVisionParser,Init);
  722.       if Parser<>NIL then begin
  723.         DeskTop^.ExecView(Parser);
  724.         Dispose(Parser,Done);
  725.       end;
  726.     end;
  727.  
  728.  
  729.   procedure Tapp.HandleEvent (var Event:TEvent);
  730.     begin
  731.  
  732.       case Event.What of
  733.  
  734.         evCommand : begin
  735.  
  736.           case (Event.Command) of
  737.  
  738.             cmParser : ShowParser;
  739.             cmScreenSave : begin
  740.               DoneVideo;
  741.               ScreenSaver^.Activ:=True;
  742.             end;
  743.             else inherited HandleEvent (Event);
  744.  
  745.           end;
  746.  
  747.         end;
  748.  
  749.         else inherited HandleEvent (Event);
  750.  
  751.       end;
  752.  
  753.     end;
  754.  
  755.  
  756. begin
  757.  
  758.    XApplic.Init;
  759.    XApplic.Run;
  760.    XApplic.Done;
  761.  
  762. end.
  763.